Skip to content

gh-149083: Convert dataclasses.MISSING and dataclasses.KW_ONLY to sentinels#149086

Merged
JelleZijlstra merged 1 commit intopython:mainfrom
JelleZijlstra:datacls-missing
Apr 30, 2026
Merged

gh-149083: Convert dataclasses.MISSING and dataclasses.KW_ONLY to sentinels#149086
JelleZijlstra merged 1 commit intopython:mainfrom
JelleZijlstra:datacls-missing

Conversation

@JelleZijlstra
Copy link
Copy Markdown
Member

@JelleZijlstra JelleZijlstra commented Apr 28, 2026

There were comments claiming these were implemented as custom classes to give a nicer
repr(), but the repr() wasn't all that nice:

>>> repr(dataclasses.MISSING)
'<dataclasses._MISSING_TYPE object at 0x1005e7e00>'
>>> repr(dataclasses.KW_ONLY)
'<dataclasses._KW_ONLY_TYPE object at 0x100884050>'

Sentinels are conceptually the right tool for these, so let's use them.

This does change the repr() of these two objects.

…to sentinels

There were comments claiming these were implemented as custom classes to give a nicer
repr(), but the repr() wasn't all that nice:

>>> repr(dataclasses.MISSING)
'<dataclasses._MISSING_TYPE object at 0x1005e7e00>'
>>> repr(dataclasses.KW_ONLY)
'<dataclasses._KW_ONLY_TYPE object at 0x100884050>'

Sentinels are conceptually the right tool for these, so let's use them.

This does change the repr() of these two objects.
@ericvsmith
Copy link
Copy Markdown
Member

Thanks, @JelleZijlstra.

My only concern: is there any chance this will cause a performance regression when importing dataclasses? I assume not, since there are no imports involved, but I thought I'd ask. People are understandably touchy about it.

@JelleZijlstra
Copy link
Copy Markdown
Member Author

It's almost certainly faster. Creating a class is quite slow; creating a sentinel is a very simple C call. From timeit it seems to be about 50x faster:

>>> timeit.timeit("class X: pass")
2.916836875025183
>>> timeit.timeit("x = sentinel('x')")
0.06976754195056856

So this might actually measurably improve import time.

Copy link
Copy Markdown
Member

@ericvsmith ericvsmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks.


def test_missing_repr(self):
self.assertIn('MISSING_TYPE object', repr(MISSING))
self.assertEqual(repr(MISSING), 'MISSING')
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea why the arguments were in the opposite order before, but changing them is a definite improvement!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And yes, I realize that wasn't really the point of this change.

@JelleZijlstra JelleZijlstra merged commit 1695221 into python:main Apr 30, 2026
97 of 101 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants